using System;
using System.Collections.Generic;
using Rhizome.Contract;
using Rhizome.Contract.Diag;
using Rhizome.Contract.Visitor;
using Rhizome.Internal;

namespace Rhizome.Model.Validation
{
	public sealed class ValidationResult : IValidationResult
	{
		public static readonly IValidationResult PlantIsNull = Error("Plant is null", 1);
		public static readonly IValidationResult EventSinkIsNull = Error("Event Sink is null", 2);
		public static readonly IValidationResult InitialStateNotSet = Error("InitialState not set", 8);
		public static readonly IValidationResult StateNotSet = Warning("State not set", 8);
		public static readonly IValidationResult StatesAreEmpty = Error("States are empty", 8);
		public static readonly IValidationResult FailStateNotSet = Warning("Fail State not set", 8);
		public static readonly IValidationResult EventNotSet = Error("Event not set", 16);
		public static readonly IValidationResult CriterionIsNull = Error("Criterion is null", 32);
		public static readonly IValidationResult PropertyNotSet = Error("Property not set", 64);
		public static readonly IValidationResult PropertyNotSetWarning = Warning("Property not set", 64);
		public static IValidationResult ActionIsNull = Error("Action is null", 256);
		public static IValidationResult ValueNotSet = Error("Value not set", 512);
		public static IValidationResult ValueNotSetWarning = Warning("Value not set", 512);
		public static IValidationResult ActiveObjectHostIsNull = Error("ActiveObjectHost is null", 1024);
		public static IValidationResult MessageSinkNotSet = Error("MessageSink is null", 2048);
		public static IValidationResult MessageNotSet = Error("Message is null", 4096);

		private ValidationResult(int errorTypeId, ValidationSeverity severity, string message)
		{
			Severity = severity;
			Message = message;
			ErrorTypeId = errorTypeId;
		}

		#region IValidationResult Members

		public ValidationSeverity Severity { get; private set; }
		public string Message { get; private set; }
		public int ErrorTypeId { get; private set; }

		#endregion

		public static IValidationResult StateNotFound(object stateId)
		{
			return Error("State '{0}' not found".With(stateId), 4);
		}

		public static IValidationResult PropertyNotFound(string property)
		{
			return Error("Property '{0}' not found".With(property), 128);
		}

		public static IValidationResult PropertyNotFound(string property, object source)
		{
			return PropertyNotFound("{0}.{1}".With(source.GetType(), property));
		}

		public static IValidationResult Error(string message, int errorTypeId)
		{
			return new ValidationResult(errorTypeId, ValidationSeverity.Error, message);
		}

		public static IValidationResult Error(string message)
		{
			return Error(message, 4096);
		}

		public static IValidationResult Warning(string message, int errorTypeId)
		{
			return new ValidationResult(errorTypeId, ValidationSeverity.Warning, message);
		}

		public static IValidationResult Warning(string message)
		{
			return Warning(message, 2048);
		}
	}

	public sealed class ValidationResultList
	{
		public ValidationResultList(IElement element, IEnumerable<IValidationResult> results)
		{
			if (element == null) throw new ArgumentNullException("element");
			if (results == null) throw new ArgumentNullException("results");

			Element = element;
			Results = results;
		}

		public IElement Element { get; private set; }
		public IEnumerable<IValidationResult> Results { get; private set; }
	}
}